/**************************************************************************
 * @file mframe.cpp
 * @brief MFrame
 *
 * @date 2008-11-01
 * Copyright Vadim A. Khohlov 2008
 *
 * Last Change: 2008-11-01 23:02:26
 **************************************************************************
*/

#include <iostream>

#include <wx/intl.h>
#include <wx/statbmp.h>
#include <wx/stattext.h>
#include <wx/sizer.h>
#include <wx/button.h>
#include <wx/font.h>
#include <wx/defs.h>
#include <wx/colour.h>
#include <wx/sound.h>
#include <wx/utils.h>
#include <wx/mediactrl.h>

/* project headers */
#include "mframe.h"
#include "keycatcher.h"
#include "dlgsetscore.h"

#include "red.xpm"
#include "green.xpm"
#include "blue.xpm"
#include "yellow.xpm"

enum
{
    TMR_ANSWERS,
    TMR_1ANSWER,
    TMR_BLOCKER
}; /* enum */

static const char **(balls[]) = 
{
    red_ball, green_ball, blue_ball, yellow_ball
}; /* static const char *balls[][] =  */

static const wxColour playerColor[] = 
{
    *wxRED, wxColour(0, 0x80, 0), *wxBLUE, wxColour(255,150,0)
}; /* static const wxColour playerColors[] =  */

static const wxString sounds[] = 
{
    wxT("red"), wxT("green"), wxT("blue"), wxT("yellow"), wxT("zero"),
    wxT("plus"), wxT("minus")
}; /* static const wxString sounds[] =  */

//MainFrame
//
BEGIN_EVENT_TABLE(MainFrame, wxFrame)
//	EVT_SIZE(MainFrame::onSize)
    EVT_KEY_DOWN(MainFrame::onKeyDown)
    EVT_KEY_UP(MainFrame::onKeyUp)
    EVT_TIMER(TMR_ANSWERS, MainFrame::onTimerAnser)
    EVT_TIMER(TMR_BLOCKER, MainFrame::onTimerBlocker)
END_EVENT_TABLE()
/**
* constructor
*/
MainFrame::MainFrame():
	wxFrame(NULL, wxID_ANY, _("Jeopardy")),
    tmrAnswers_(this, TMR_ANSWERS),
    tmr1Answer_(this, TMR_1ANSWER),
    tmrBlocker_(this, TMR_BLOCKER),
    isPlayersBlocked(false)
{
    //mCtrl = new wxMediaCtrl(this, wxID_ANY, wxT("zero.wav"),
            //wxDefaultPosition, wxDefaultSize, 0, wxMEDIABACKEND_GSTREAMER);
    //bool isLoaded = mCtrl->Load(wxT("zero.wav"));
    //std::cout << "is loaded: " << isLoaded << '\n';
    wxBoxSizer *tops = new wxBoxSizer(wxHORIZONTAL);
    
    //left part - scores
    wxBoxSizer *vs = new wxBoxSizer(wxVERTICAL);
  
    wxFont fnt; 
    wxBoxSizer *hs;
    vs->AddStretchSpacer();
    for(unsigned i = 0; i < sizeof(balls)/sizeof(balls[0]); ++i)
    {
        hs = new wxBoxSizer(wxHORIZONTAL);
        hs->Add(new wxStaticBitmap(this, wxID_ANY, balls[i]), 0, wxALL, 2);
        edScore_[i] = new wxStaticText(this, wxID_ANY, _("00000"));
        fnt = edScore_[i]->GetFont();
        fnt.SetPointSize(36);
        edScore_[i]->SetFont(fnt);
        edScore_[i]->SetForegroundColour(playerColor[i]);
        hs->Add(edScore_[i], 0, wxALL, 3);
        vs->Add(hs, 0, wxALL, 3);
        vs->AddStretchSpacer();
    } /*     for(unsigned i = 0; i < sizeof(balls)/sizeof(balls[0]); ++i) */

    tops->Add(vs, 0, wxEXPAND, 3);

    //right part - indicators
    vs = new wxBoxSizer(wxVERTICAL);
    stThemeNum_ = new wxStaticText(this, wxID_ANY, _("Question N1"), 
            wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
    fnt = stThemeNum_->GetFont();
    fnt.SetPointSize(24);
    stThemeNum_->SetFont(fnt);
    vs->Add(stThemeNum_, 0, wxCENTER, 2);

    stQuestCost_ = new wxStaticText(this, wxID_ANY, _("10"), 
            wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
    fnt = stQuestCost_->GetFont();
    fnt.SetPointSize(24);
    stQuestCost_->SetFont(fnt);
    vs->Add(stQuestCost_, 0, wxCENTER, 2);

    hs = new wxBoxSizer(wxHORIZONTAL);
    //hs->AddSpacer(10);
    stTimer_ = new wxStaticText(this, wxID_ANY, _("0"), 
            wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE| wxRAISED_BORDER);
    fnt = stTimer_->GetFont();
    fnt.SetWeight(wxFONTWEIGHT_BOLD);
    fnt.SetPointSize(240);
    stTimer_->SetFont(fnt);
    hs->Add(stTimer_, 2, wxEXPAND | wxCENTER | wxALL, 2);
    //hs->AddSpacer(10);
    vs->Add(hs, 2, wxEXPAND | wxALL, 2);

    stStateInfo_ = new wxStaticText(this, wxID_ANY, _("State:"));
    vs->Add(stStateInfo_);

    tops->Add(vs, 1, wxEXPAND, 3);

    SetSizer(tops);
    tops->SetSizeHints(this);
    SetMinSize(wxSize(640, 480));

#ifdef __WXGTK__
    keyCatcher_ = new KeyCatcher(this);
    keyCatcher_->SetSize(0,0);
    keyCatcher_->SetFocus();
#endif

} /* MainFrame() */

void
MainFrame::onSize(wxSizeEvent &evt)
{
    //int w, h;
    //stTimer_->GetSize(&w, &h);
    //std::cout << "size " << w << "x" << h << "\n";
    evt.Skip();    
} /* MainFrame::onSize(wxSizeEvent &evt) */

void
MainFrame::onKeyDown(wxKeyEvent &evt)
{
    if (isPlayersBlocked || 
            (gamer_.state() != SIGamer::QREADING && 
             gamer_.state() != SIGamer::ASWAIT))
        evt.Skip();
    else
    {
        SIGamer::InSignal signal = SIGamer::GOTO;
        switch(evt.GetKeyCode())
        {
            case '7':
            case WXK_NUMPAD7:
                signal = SIGamer::REDPLAYER;
                break;
            case '1':
            case WXK_NUMPAD1:
                signal = SIGamer::GREENPLAYER;
                break;
            case '3':
            case WXK_NUMPAD3:
                signal = SIGamer::BLUEPLAYER;
                break;
            case '9':
            case WXK_NUMPAD9:
                signal = SIGamer::YELLOWPLAYER;
                break;
        } /*     switch(evt.GetKeyCode()) */

        //skip nonplayers' keys and avoid multiple pressing
        if (signal != SIGamer::GOTO && !countPressing_[signal]++)
        {
            tmrAnswers_.Stop();
            playSound(static_cast<Sounds>(signal));
            gamer_.nextState(signal);
            showState();
        } /*         if (signal != SIGamer::GOTO) */
    } /*     else */
} /* MainFrame::onKeyDown(wxKeyEvent &evt) */

void
MainFrame::onKeyUp(wxKeyEvent &evt)
{
    if (evt.GetKeyCode() == '0' || evt.GetKeyCode() == WXK_NUMPAD0)
    {
        gamer_.reset();
        tmrAnswers_.Stop(); // if we jump here from ASWAIT state
        countPressing_[0] = countPressing_[1] = 
        countPressing_[2] = countPressing_[3] = 0; 
        showState();
    } /* if (evt.GetKeyCode() == '0' */
    else if (gamer_.state() == SIGamer::A1WAIT)
    {
        switch (evt.GetKeyCode())
        {
            case '-':
            case WXK_NUMPAD_SUBTRACT:
                playSound(SND_MINUS);
                gamer_.nextState(SIGamer::MINUS);
                break;
            case '=':
            case WXK_NUMPAD_ADD:
                playSound(SND_PLUS);
                //we jumps to READING state - so players can press they keys
                countPressing_[0] = countPressing_[1] = 
                countPressing_[2] = countPressing_[3] = 0; 
                gamer_.nextState(SIGamer::PLUS);
                break;
        } /*         switch (evt.GetKeyCode()) */
        edScore_[gamer_.curPlayer()]->SetLabel(wxString::Format(_T("%d"),
                    gamer_.playerScore(static_cast<SIGamer::Player>(gamer_.curPlayer()))));
        showState();
    } /*     if (gamer_.state() == SIGamer::A1WAIT) */
    else if (evt.GetKeyCode() == WXK_RETURN || evt.GetKeyCode() == WXK_NUMPAD_ENTER)
    {
        gamer_.nextState();
        showState();
    } /* if (evt.GetKeyCode() == WXK_RETURN || evt.GetKeyCode() == WXK_NUMPAD_ENTER) */
    else if (evt.GetKeyCode() == '*' || evt.GetKeyCode() == WXK_NUMPAD_MULTIPLY)
    {
        int i;
        for(i = 0; i < 4; ++i)
            playerScore_[i] = wxString::Format(wxT("%d"), 
                    gamer_.playerScore(static_cast<SIGamer::Player>(i)));
        if (DlgSetScore(this, &playerScore_).ShowModal() == wxID_OK)
        {
            for(i = 0; i < 4; ++i)
            {
                long val;
                playerScore_[i].ToLong(&val);
                gamer_.setPlayerScore(static_cast<SIGamer::Player>(i), val);
            } /*             for(int i = 0; i < 4; ++i) */
            showState();
        } /* if (DlgSetScore(this, &playerScore).ShowModal() == wxID_OK) */
    } /* if (evt.GetKeyCode() == '*' */
    else
        evt.Skip();
} /* MainFrame::onKeyUp(wxKeyEvent &evt) */

void
MainFrame::showState()
{
    static wxString stateName[] =
    {
        wxTRANSLATE("Init"),
        wxTRANSLATE("Startgame"),
        wxTRANSLATE("Quest reading"),
        wxTRANSLATE("Answers wait"),
        wxTRANSLATE("One Answer wait")
    }; /*     static wxString stateName[] = */

    static const wxColour *colors[] = {wxRED, wxGREEN, wxBLUE};

    stStateInfo_->SetLabel(wxString::Format(_("State: %s"), stateName[gamer_.state()].c_str()));
    stStateInfo_->Update();

    switch(gamer_.state())
    {
        case SIGamer::INIT:
            break;
        case SIGamer::QREADING:
            for(int i = 0; i < 4; ++i)
                edScore_[i]->SetLabel(wxString::Format(_T("%d"),
                            gamer_.playerScore(static_cast<SIGamer::Player>(i))));
            stThemeNum_->SetLabel(wxString::Format(_("Theme N %d"),
                        gamer_.curThemeNum()));
            stThemeNum_->Update();
            stQuestCost_->SetLabel(wxString::Format(_("Quest\'s cost %d"),
                        gamer_.curQCost()));
            stQuestCost_->Update();
            stTimer_->SetForegroundColour(*wxBLACK);
            stTimer_->SetLabel(_("R"));
            stTimer_->Update();
            tmrAnswers_.Stop(); // if we jump here from ASWAIT state
            //countPressing_[0] = countPressing_[1] = countPressing_[2] = countPressing_[3] = 0; 
            GetSizer()->RecalcSizes();
            break;
        case SIGamer::ASWAIT:
            ansLeft_ = 5;
            stTimer_->SetForegroundColour(*wxBLACK);
            showAnswersTimeLeft();
            tmrAnswers_.Start(1000);
            break;
        case SIGamer::A1WAIT:
            stTimer_->SetForegroundColour(playerColor[gamer_.curPlayer()]);
            stTimer_->SetLabel(_("?"));
            stTimer_->Update();
            break;
    } /*     switch(gamer.state()) */
} /* MainFrame::showState */

void MainFrame::showAnswersTimeLeft()
{
    stTimer_->SetLabel(wxString::Format(_T("%d"), ansLeft_));
    stTimer_->Update();
} /* void MainFrame::showAnswersTimeLeft() */

void
MainFrame::onTimerAnser(wxTimerEvent &evt)
{
    --ansLeft_;
    showAnswersTimeLeft();
    if(!ansLeft_)
    {
        tmrAnswers_.Stop();
        gamer_.nextState();
        isPlayersBlocked = true;
        tmrBlocker_.Start(5000);
        //mCtrl->Play();
        playSound(SND_ZERO);
        //we jumps to READING state - so players can press they keys
        countPressing_[0] = countPressing_[1] = 
        countPressing_[2] = countPressing_[3] = 0; 
        showState();
    } /*     if(--ansLeft_) */
} /* MainFrame::timerAnser(wxTimerEvent &evt) */

void
MainFrame::playSound(Sounds iSoundNum)
{
    wxString soundFile(wxString::Format(_T("aplay ./sounds/%s.wav"), sounds[iSoundNum].c_str()));
#ifdef __WXGTK__            
    wxExecute(soundFile); 
#else   //Windows
    wxSound(soundFile).Play()
#endif
} /* MainFrame::playSound */

void
MainFrame::onTimerBlocker(wxTimerEvent &evt)
{
    //unblock players after 5 s
    isPlayersBlocked = false;
} /* MainFrame::onTimerBlocker(wxTimerEvent &evt) */

